package random;

import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import javax.swing.JFrame;
import java.util.Scanner;

public class Main {
	// private static int minX = 15;
	// private static int maxX = 1425;
	// private static int minY = 15;
	// private static int maxY = 840;
	private static int amount;

	private static final Stats min = new Stats();

	private static final Stats max = new Stats();

	private static final Stats avg = new Stats();
	// private static final Stats moment2 = new Stats();
	// private static final Stats moment3 = new Stats();
	// private static final Stats moment4 = new Stats();
	static {
		min.endLength = Integer.MAX_VALUE;
		min.manEndLength = Integer.MAX_VALUE;
		min.pathLength = Integer.MAX_VALUE;
		min.stepLength = Integer.MAX_VALUE;
		avg.n = 0;
	}

	private static int running = 0;

	private static int cpus;
	
	private static int count=0;

	private static final int[][] stepSizes = {{1},{1000000,1000001},{100,10001},{1,1000,1,999}};

	public static void main(String[] args) throws InterruptedException {
		long  end;
		amount = 5000000;
		final long begin = System.currentTimeMillis();

		final ThreadGroup threadGroup = new ThreadGroup("threads");
		cpus = Runtime.getRuntime().availableProcessors();
		for (int j = 0; j < cpus; j++) {
			final int thrNr = j;

			Runnable run = new Runnable() {

				@SuppressWarnings("boxing")
				@Override
				public void run() {
					System.out.println(thrNr);
					final RandomWalk rw = new RandomWalk();
					final RandomWalkFast rwf = new RandomWalkFast();
					Stats mi = new Stats();
					Stats ma = new Stats();
					Stats av = new Stats();
					mi.endLength = Integer.MAX_VALUE;
					mi.manEndLength = Integer.MAX_VALUE;
					mi.pathLength = Integer.MAX_VALUE;
					mi.stepLength = Integer.MAX_VALUE;
					av.n = 0;
					Stats curr = new Stats();
					for (int i = 0; i < amount / cpus; ++i) {
						try {
//							curr = rw.CalculateLengthASaw(stepSizes[1]);
							curr = rwf.calculateLengthASawShort(stepSizes[1]);
//							curr = rwf.calculateLengthASawLong(stepSizes[3]);
//							curr = rw.CalculateLengthASawTri(stepSizes[0]);
//							curr = rw.CalculateLengthSawHex();
//							curr = rw.CalculateLengthSawHex2();
							mi.min(curr);
							av.add(curr);
							ma.max(curr);

						} catch (ArrayIndexOutOfBoundsException e) {
//							e.printStackTrace();
//							throw e;
							if (++count >=(amount/10000) && RandomWalk.SIZE < 1073741824) {
								count = 0;
								RandomWalk.SIZE <<= 1;
								System.out.println(thrNr + ": " + RandomWalk.SIZE);
							}
						}
						if ((thrNr == 0 ||running != cpus) && (i + 1) % (amount / cpus / 100) == 0 ){
							long p = (i + 1) / (amount / cpus / 100);
							long t = System.currentTimeMillis();
							System.out.print(thrNr + ": " + p +"% est. ");
							System.out.format("%1$tk:%1$tM:%1$tS / %2$tk:%2$tM:%2$tS exp. %3$10.3f\n"
									,(100l-p)*(t-begin)/p-3600000l
									,100l*(t-begin)/p-3600000l
									,(float)av.stepLength/(float)av.n);
						}
					}
					synchronized (Main.class) {
						min.min(mi);
						avg.add(av);
						max.max(ma);
					}
					synchronized (threadGroup) {
						System.out.println(thrNr);
						running--;
						if (running == 0)
							threadGroup.notify();
					}
				}
			};
			Thread thread = new Thread(threadGroup, run);
			thread.start();
			running++;
		}
		synchronized (threadGroup) {
			threadGroup.wait();
		}
		end = System.currentTimeMillis();

		System.out.println("Min end: " + min.endLength);
		System.out.println("Min manhattan: " + min.manEndLength);
		System.out.println("Min path: " + min.pathLength);
		System.out.println("Min step: " + min.stepLength);
		System.out.println("Max end: " + max.endLength);
		System.out.println("Max manhattan: " + max.manEndLength);
		System.out.println("Max path: " + max.pathLength);
		System.out.println("Max step: " + max.stepLength);
		System.out.println("Average length end: " + avg.endLength / avg.n);
		System.out.println("Average length manhattan: " + (double) avg.manEndLength / (double) (avg.n));
		System.out.println("Average length path: " + (double) avg.pathLength / (double) (avg.n));
		double mean = avg.stepLength / (double) (avg.n);
		System.out.println("Average length step: " + mean);
		System.out.print("Time: " + (end - begin) + "ms. ");
		System.out.format("%1$tk:%1$tM:%1$tS.%1$tL",(end - begin)-3600000l);
		System.out.println();
		System.out.println("Grid size: " + RandomWalk.SIZE);
	}
}
